package org.tom.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.tom.basic.exception.MyException;
import org.tom.basic.util.HttpClientUtils;
import org.tom.basic.util.JsonResult;
import org.tom.basic.util.MD5Utils;
import org.tom.user.constant.UserConstant;
import org.tom.user.domain.Logininfo;
import org.tom.user.domain.User;
import org.tom.user.domain.WxUser;
import org.tom.user.dto.LoginDto;
import org.tom.user.mapper.LogininfoMapper;
import org.tom.user.mapper.UserMapper;
import org.tom.user.mapper.WxUserMapper;
import org.tom.user.service.ILoginService;
import org.tom.user.util.SaveUserAndLogininfo;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    // 普通登录的方法
    @Override
    public Map<String, Object> login(LoginDto loginDto) {
        // 校验
        // 非空校验
        if (StringUtils.isEmpty(loginDto.getUsername()) || StringUtils.isEmpty(loginDto.getPassword()) || StringUtils.isEmpty(loginDto.getType())){
            throw new MyException("参数请填写完整");
        }
        // 根据用户名和类型，查询logininfo
        Logininfo logininfo = logininfoMapper.findByUsernameAndType(loginDto);
        // 查不到提示用户名不存在
        if (logininfo == null){
            throw new MyException("用户名不存在");
        }
        // 查得到，判断密码是否一致
        String salt = logininfo.getSalt();
        if (!MD5Utils.encrypByMd5(salt+loginDto.getPassword()).equals(logininfo.getPassword())){
            throw new MyException("密码不正确");
        }
        // 没有问题就将用户信息存入redis中
        // String token = UUID.randomUUID().toString()生成随机数
        String token = UUID.randomUUID().toString();
        //  对象存储到redis中只有序列化后才可以存储
        //  在basedomain中实现serz...接口
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
        // 将map中存储值
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        map.put("logininfo", logininfo);
        return map;
    }


    // 微信登录的方法
    @Override
    public JsonResult loginWechat(Map<String, String> params) {
        String code = params.get("code");
        String binderUrl = params.get("binderUrl");
        // 判断code是否为空，为空则是ture
        if (StringUtils.isEmpty(code)){
            throw new MyException("code为空");
        }
        // 通过code获取token令牌 用工具类httpCLientUtils调用方法httpGet返回json格式的字符串
        // APPID,SECRET都是公司特有的
        String replace = HttpClientUtils.httpGet(UserConstant.TOKEN_BY_CODE
                .replace("APPID", UserConstant.APPID)
                .replace("SECRET", UserConstant.SECRET)
                .replace("CODE", code));
        // 使用fastjson将字符串转换为json对象
        JSONObject jsonObject = JSONObject.parseObject(replace);

        // 获取到的json对象中，返回值调用方法getString获取令牌access_token和openid字符串
        //	access_token为令牌
        //	openid获取openid
        String access_token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");

        // 通过openid判断wxUser用户是否存在
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);
        // 判断是否存在
        if (wxUser != null && !StringUtils.isEmpty(wxUser.getUser_id())){
            // 如果非空就存入redis
            Logininfo logininfo = logininfoMapper.findByUser_id(wxUser.getUser_id());
            // 如果没有问题，把用户信息存入redis中
            String token = UUID.randomUUID().toString();
            //  对象存储到redis，需要序列化
            redisTemplate.opsForValue().set(token,
                    logininfo,
                    30,
                    TimeUnit.MINUTES);

            Map<String, Object> map = new HashMap<>();
            // map中应该存token， 用户信息
            map.put("token",token);

            //  不能让前端看到用户机密信息
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            map.put("logininfo", logininfo);
            return JsonResult.me().setResultObj(map);
        }else {
            // 当前在表中没有找到，返回对象中为在binderUrl中将openid和access_token传到前端
            binderUrl = binderUrl + "?accessToken=" + access_token + "&openId=" + openid;
            return JsonResult.me().setMsg("请先绑定电话").setResultObj(binderUrl);
        }
    }

    // 绑定电话号码的方法
    @Override
    @Transactional
    public JsonResult binderWechat(Map<String, String> params) {
        // 判断手机号,验证码是否为空
        String phone = params.get("phone");
        String verifyCode = params.get("verifyCode");
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode)){
            throw new MyException("手机号或者验证码不能为空");
        }

        // 判断是否可以获取到验证码
        Object o = redisTemplate.opsForValue().get(UserConstant.BINDER_PREFIX + phone);
        if (o == null){
            // 在redis中没有获取到验证码，提示用户获取验证码
            throw new MyException("请获取验证码再进行绑定");
        }

        // 判断验证码输入是否正确
        String code = o.toString().split(":")[1];
        System.out.println(code);
        if (!code.equals(verifyCode)){
            throw new MyException("验证码不正确");
        }

        System.out.println("绑定成功");


        String accessToken = params.get("accessToken");
        String openId = params.get("openId");

        // 向微信端发送请求，获取用户信息,返回的结果是json格式的字符串
        String s = HttpClientUtils.httpGet(UserConstant.GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId)
        );

        //  将json格式的字符串转化为对象，阿里巴巴提供的方法需要导包
        JSONObject jsonObject = JSONObject.parseObject(s);

        // 新建WxUser对象将获取到的微信用户信息存到对象中
        WxUser wxUser = new WxUser();
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));


        // 判断手机号是否被注册,注册过直接将获取到的用户信息存到WxUser中
        User userbyPhone = userMapper.findByPhone(phone);
        if (userbyPhone != null){
            wxUser.setUser_id(userbyPhone.getId());
            wxUserMapper.add(wxUser);
            Logininfo logininfo = logininfoMapper.findByUser_id(userbyPhone.getId());
            // 新建map将登录信息存入map中返回到前端
            Map<Object, Object> map = new HashMap<>();
            map.put("logininfo",logininfo);
            String token = UUID.randomUUID().toString();
            map.put("token", token);
            return JsonResult.me().setResultObj(map);
        }



        // 调用方法将电话号码和头像存入User的对象中
        User user = SaveUserAndLogininfo.wxUser2User(phone, wxUser.getHeadimgurl());

        // 调用方法将user中的信息存入Logininfo对象中
        Logininfo logininfo = SaveUserAndLogininfo.user2Logininfo(user);
        // 将对象logininfo对象存入数据库返回自增的主键
        logininfoMapper.add(logininfo);

        // 返回的自增主键存入user对象之中
        user.setLogininfo(logininfo);

        // 将user对象存入数据库，返回子自增主键存入wxUser对象之中
        userMapper.add(user);
        wxUser.setUser_id(user.getId());
        // 将对象wxUser存入数据库中
        wxUserMapper.add(wxUser);

        // 新建map将登录信息存入map中返回到前端
        Map<Object, Object> map = new HashMap<>();
        map.put("logininfo",logininfo);
        String token = UUID.randomUUID().toString();
        map.put("token", token);
        return JsonResult.me().setResultObj(map);
    }
}
